<template>
    <div class="generic-type-declare">
        <div class="flex-v-center text-placeholder" v-if="app.dependencyInitializing">
            <tnxel-icon class="mx-1" value="Loading" style="margin-top: 1px;"/>
            <span class="fs-p90">依赖库加载中</span>
        </div>
        <template v-else>
            <div class="flex-1 nowrap cursor-default me-2"
                :title="joinCaption(false)"
                v-if="types.length">
                {{ joinCaption(true) }}
            </div>
            <div class="text-placeholder me-2" v-else>&lt;无&gt;</div>
            <tnxel-button class="px-2"
                type="primary"
                text
                bg
                icon="MoreFilled"
                @click="toUpdate"
                v-if="updatable"/>
            <tnxel-dialog v-model="dialog.visible"
                :buttons="dialog.buttons"
                :title="title"
                :width="660"
            >
                <tnxel-edit-table ref="table"
                    :data="types"
                    add-text="添加泛型"
                    :new-row="newType"
                    :rules="rules"
                    sortable
                >
                    <el-table-column label="序号" type="index" align="center" width="60"/>
                    <el-table-column label="参数" prop="parameter" align="center">
                        <template #default="{row}">
                            <el-input v-model="row.parameter"/>
                        </template>
                    </el-table-column>
                    <el-table-column label="限定" prop="extended" align="center" width="100">
                        <template #default="{row, $index}">
                            <tnxel-select v-model="row.extended"
                                :id="$index"
                                :items="extendedItems"
                                empty
                                placeholder=""
                                :change="onExtendedChange"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column label="类型" prop="typeId" width="200">
                        <template #default="{row}">
                            <LogicTypeSelect v-model="row.typeId"
                                :app="app"
                                :kind="TypeKind.GENERIC"
                                @change="onTypeIdChange(row)"
                            />
                        </template>
                    </el-table-column>
                    <el-table-column label="数组" prop="arrayed" align="center" width="60">
                        <template #default="{ row }">
                            <ArrayedSelect v-model="row.arrayed" :property="row"/>
                        </template>
                    </el-table-column>
                </tnxel-edit-table>
            </tnxel-dialog>
        </template>
    </div>
</template>

<script>
import tnx from '@/tnx.js';
import ModelingApp from '@/logic/modeling/entity/ModelingApp.js';
import TypeKind from '@/logic/modeling/enums/TypeKind.js';
import GenericType from '@/logic/modeling/entity/GenericType.js';
import GenerateUtil from '@/logic/modeling/util/generate.js';

import ArrayedSelect from './ArrayedSelect.vue';
import LogicTypeSelect from './LogicTypeSelect.vue';

export default {
    name: 'GenericTypeDeclare',
    components: {ArrayedSelect, LogicTypeSelect},
    props: {
        modelValue: {
            type: Array,
            default: () => [],
        },
        app: {
            type: ModelingApp,
            required: true,
        },
        title: {
            type: String,
            default: '泛型声明',
        },
        updatable: {
            type: Boolean,
            default: true,
        },
    },
    data() {
        return {
            TypeKind,
            types: [],
            extendedItems: [{
                text: 'extends',
                value: 'true',
            }, {
                text: 'super',
                value: 'false',
            }],
            rules: {
                parameter: [tnx.app.validator.requiredRule, tnx.app.validator.symbolRule],
            },
            dialog: {
                visible: false,
                buttons: tnx.getDefaultDialogButtons('confirm', this.toSubmitUpdate),
            },
        };
    },
    watch: {
        modelValue() {
            this.initTypes();
        },
    },
    mounted() {
        this.initTypes();
    },
    methods: {
        joinCaption(simple) {
            return GenerateUtil.generateGenericTypesCaption(this.app, this.modelValue, simple);
        },
        initTypes() {
            this.types.length = 0;
            for (let modelType of this.modelValue) {
                let type = modelType.clone();
                this.assignName(type, modelType);
                this.types.push(type);
            }
        },
        toUpdate() {
            this.dialog.visible = true;
        },
        newType() {
            let type = new GenericType();
            if (!this.types.length) {
                type.parameter = 'T';
            }
            return type;
        },
        onExtendedChange(item, rowIndex) {
            let row = this.types[rowIndex];
            if (row.extended === '') {
                row.typeId = '';
                this.assignName(row, {});
            }
        },
        assignName(targetType, sourceType) {
            targetType.packageName = sourceType.packageName || '';
            targetType.simpleName = sourceType.simpleName || '';
            targetType.name = sourceType.getName ? sourceType.getName() : (sourceType.name || '');
        },
        onTypeIdChange(row) {
            if (row.typeId) {
                let refClass = this.app.findClass(row.typeId, true, true);
                if (refClass) {
                    this.assignName(row, refClass);
                    if (row.extended === null || row.extended === '') {
                        row.extended = 'true';
                    }
                    return;
                }
            }
            this.assignName(row, {});
            row.extended = null;
        },
        toSubmitUpdate(yes) {
            if (yes) {
                if (!this.$refs.table.validateTable()) {
                    return false;
                }
                let types = [];
                for (let type of this.types) {
                    if (type.extended === '') {
                        type.extended = null;
                    }
                    if ((type.extended === null && type.typeId) || (type.extended !== null && !type.typeId)) {
                        tnx.error('限定和类型必须同时为空或均不为空');
                        return false;
                    }
                    type = type.clone();
                    types.push(type);
                }
                this.$emit('update:modelValue', types);
            }
        },
    }
}
</script>

<style lang="scss">
.generic-type-declare {
    display: flex;
    align-items: center;
}
</style>
